package com.yami.shop.api.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yami.shop.api.manager.ReadMessage;
import com.yami.shop.bean.dto.RedPackerIsUnpack;
import com.yami.shop.bean.dto.UnPackRedDto;
import com.yami.shop.bean.dto.red.RedPacketBasic;
import com.yami.shop.bean.dto.red.RedPacketInfoDto;
import com.yami.shop.bean.enums.SceneType;
import com.yami.shop.bean.enums.TradeType;
import com.yami.shop.bean.event.AssetTrendsEvent;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.vo.AssetTrendsVO;
import com.yami.shop.bean.vo.RedPacketInfoVo;
import com.yami.shop.bean.vo.RedPacketUserVo;
import com.yami.shop.bean.vo.RedPacketVo;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.response.ServerResponseEntity;
import com.yami.shop.common.util.DataWebService;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.common.util.StringUtils;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.dao.RedPacketInfoMapper;
import com.yami.shop.personnft.common.controller.BaseController;
import com.yami.shop.personnft.common.dao.PersonNftAccountMapper;
import com.yami.shop.personnft.common.dao.PersonNftApplyMapper;
import com.yami.shop.personnft.common.model.PersonNft;
import com.yami.shop.personnft.common.model.PersonNftAccount;
import com.yami.shop.personnft.common.service.PersonNftService;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.security.common.manager.PasswordManager;
import com.yami.shop.service.*;
import com.yami.shop.user.common.model.UserGasInfo;
import com.yami.shop.user.common.model.UserGasLog;
import com.yami.shop.service.ChannelUserRelationRecordService;
import com.yami.shop.user.common.service.UserBalanceService;
import com.yami.shop.user.common.service.UserGasInfoService;
import com.yami.shop.user.common.service.UserGasLogService;
import com.yami.shop.util.RedPacketUtils;
import groovy.lang.Tuple;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jodd.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yami.shop.common.response.ServerResponseEntity.fail;
import static com.yami.shop.common.response.ServerResponseEntity.success;
import static com.yami.shop.util.RedPacketUtils.*;

@RestController
@RequestMapping("/dtc/redpacket")
@Tag(name = "红包")
@Log4j2
public class RedPacketInfoController extends BaseController {

    @Autowired
    private RedPacketInfoService redPacketInfoService;
    @Autowired
    private UserGasLogService userGasLogService;
    @Autowired
    private ReadMessage readMessage;
    @Autowired
    private UserService userService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private PasswordManager passwordManager;
    @Autowired
    private UserGasInfoService userGasInfoService;
    @Autowired
    private ChannelUserRelationRecordService channelUserRelationRecordService;
    @Autowired
    private ShopConfig shopConfig;
    @Autowired
    private DataWebService dataWebService;
    @Autowired
    private UserBalanceService userBalanceService;
    @Autowired
    private RedPacketRecordService redPacketRecordService;
    @Autowired
    private RedPacketInfoMapper redPacketInfoMapper;
    @Autowired
    private PersonNftService personNftService;
    @Autowired
    private PersonNftApplyMapper personNftApplyMapper;
    @Autowired
    private PersonNftAccountMapper personNftAccountMapper;
    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedPacketUtils redPacketUtils;
    @Autowired
    private ProductService productService;
    @Autowired
    private ProdNftService prodNftService;
    @Autowired
    private RedTokenRecordService redTokenRecordService;
    @Autowired
    private MeltCloudUserRemarkService userRemarkService;

    private String applyId = "";

    @GetMapping("/records/{id}")
    @Operation(summary = "红包打开记录", description = "红包打开记录")
    public ServerResponseEntity<RedPacketVo> records(@PathVariable("id") Long id) {
        String userId = SecurityUtils.getUser().getUserId();
//        String codeAndUserId = RedisUtil.get("channelCode::" + userId);
//        if (ObjectUtil.isEmpty(codeAndUserId)) {
//            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.open.check"));
//        }
        RedPacketVo records = redPacketInfoService.records(id, "");
        // 获取用户备注
        QueryWrapper<MeltCloudUserRemark> meltCloudUserRemarkQueryWrapper = new QueryWrapper<>();
        meltCloudUserRemarkQueryWrapper.eq("type",1);
        meltCloudUserRemarkQueryWrapper.eq("user_id",userId);
        meltCloudUserRemarkQueryWrapper.eq("obj_id",records.getUserId());
        meltCloudUserRemarkQueryWrapper.last("limit 1");
        MeltCloudUserRemark one = userRemarkService.getOne(meltCloudUserRemarkQueryWrapper);
        if(ObjectUtil.isNotEmpty(one)){
            records.setUserName(one.getRemark());
        }
        records.getUserRecords().forEach(s->{
            // 获取用户备注
            QueryWrapper<MeltCloudUserRemark> meltCloudUserRemarkQueryWrapper1 = new QueryWrapper<>();
            meltCloudUserRemarkQueryWrapper1.eq("type",1);
            meltCloudUserRemarkQueryWrapper1.eq("user_id",userId);
            meltCloudUserRemarkQueryWrapper1.eq("obj_id",s.getUserId());
            meltCloudUserRemarkQueryWrapper1.last("limit 1");
            MeltCloudUserRemark one1 = userRemarkService.getOne(meltCloudUserRemarkQueryWrapper1);
            if(ObjectUtil.isNotEmpty(one1)){
                s.setUserName(one1.getRemark());
            }
        });
        // 获取当前人获取金额
        RedPacketUserVo redPacketUserVo = records.getUserRecords().stream().filter(s -> s.getUserId().equals(userId)).findFirst().orElse(null);
        if (ObjectUtil.isNotEmpty(redPacketUserVo)) {
            records.setThisAmount(redPacketUserVo.getAmount());
        }
        return success(records);
    }


    @GetMapping("/getRedPackets")
    @Operation(summary = "我收到的红包列表", description = "我收到的红包列表")
    public ServerResponseEntity<IPage<RedPacketInfoVo>> getRedPackets(PageParam<RedPacketInfoVo> page, @RequestParam(name = "userId") String userId,
                                                                      @RequestParam(name = "year", required = false) String year,
                                                                      @RequestParam("type") String type) {
        String authUserId = SecurityUtils.getUser().getUserId();
//        String codeAndUserId = RedisUtil.get("channelCode::" + userId);
        return success(redPacketInfoService.getRedPackets(page, authUserId, type, year));
    }

    @GetMapping("/sendRedPackets")
    @Operation(summary = "发出的红包列表", description = "发出的红包列表")
    public ServerResponseEntity<IPage<RedPacketInfoVo>> sendRedPackets(PageParam<RedPacketInfoVo> page,
                                                                       @RequestParam(name = "userId") String userId,
                                                                       @RequestParam(name = "year", required = false) String year,
                                                                       @RequestParam("type") String type) {
        String authUserId = SecurityUtils.getUser().getUserId();
        return success(redPacketInfoService.sendRedPackets(page, authUserId, type, year));
    }

    @GetMapping("/sendRedListByyears")
    @Operation(summary = "发出的红包列表", description = "发出的红包列表")
    public ServerResponseEntity<IPage<RedPacketInfoVo>> sendRedListByyears(
            PageParam<NotifyLog> page,
            @RequestParam(name = "userId") String userId,
            @RequestParam(name = "year", required = false) String year,
            @RequestParam("type") String type) {

        return success(redPacketInfoService.sendRedListByyears(userId, type, year));
    }
//    ublic IPage<NotifyLog> pageByParam(PageParam<com.yami.shop.bean.model.NotifyLog> page, OrderParam orderParam

    /**
     * 功能描述: 人民币红包
     *
     * @Author: LSR
     * @Date: 2023/2/24 10:59
     */
    @PostMapping("/send")
    @Operation(summary = "发送红包")
    public ServerResponseEntity<RedPacketVo> follow(@RequestBody @Valid RedPacketInfoDto red) {
        if (red.getTotalAmount() == 0 || red.getTotalPacket() == 0) {
            throw new YamiShopBindException("yami.sys.illegalArgument");
        }
        String userId = SecurityUtils.getUser().getUserId();
        String decryptPassword = passwordManager.decryptPassword(red.getPassword());
        User user = userService.getById(userId);
        if (!passwordEncoder.matches(decryptPassword, user.getPayPassword())) {
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.password.check"));
        }
        return success(redPacketInfoService.sendRedPacket(red));
    }

    @PostMapping("/isUnpack")
    @Operation(summary = "是否可拆")
    public ServerResponseEntity<RedPackerIsUnpack> isUnpack(@RequestParam("userId") String userId,
                                                            @RequestParam("redPacketId") Long redPacketId) {
        return redPacketInfoService.rodRedPacket(redPacketId, userId);
    }

    @PostMapping("/isOneUnpack")
    @Operation(summary = "单聊红包可拆")
    public ServerResponseEntity isOneUnpack(@RequestParam("userId") String userId,
                                            @RequestParam("redPacketId") Long redPacketId) {
        return redPacketInfoService.rodOneRedPacket(redPacketId, userId);
    }

    /**
     * 功能描述: 拆红包
     *
     * @Author: LSR
     * @Date: 2023/2/24 10:59
     */
    @PostMapping("/unpack")
    @Operation(summary = "拆红包")
    public ServerResponseEntity<Double> unpackRedPacket(@RequestBody UnPackRedDto dto) {
        dto.setUserId(SecurityUtils.getUser().getUserId());
        String uuid = IdUtil.randomUUID();
        Boolean aBoolean = RedisUtil.VALUE_REDIS_TEMPLATE.setIfAbsent("RED_PACKET:" + dto.getRedPacketId() + "-" + dto.getUserId(), uuid);
        if (!aBoolean) {
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.request.repeat"));
        }
        try {
            RedPacketInfo byId = redPacketInfoService.getById(dto.getRedPacketId());
            if("1".equals(dto.getChatType()) && dto.getUserId().equals(byId.getUserId())){
                return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.open.myself"));
            }
            if (byId.getStatus() != 1) {
                return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.expire"));
            }
            if(ObjectUtil.isEmpty(SecurityUtils.getUser().getXsUserId())){
                return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.open.check.realname"));
            }
            if("1".equals(byId.getType())){
                Boolean hasAllAddress = channelUserRelationRecordService.isHasAllAddress(dto.getUserId(), byId.getChainCode(), byId.getChannelCode(), byId.getChainType());
                if (!hasAllAddress) {
                    return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.open.check"));
                }
            }
            // 判断 是否拆过红包
            Object redPackage = redisTemplate.opsForHash().get(RedPacketUtils.RED_PACKAGE_CONSUME_KEY + dto.getRedPacketId(), dto.getUserId());
            if (ObjectUtil.isNotEmpty(redPackage)) {
                return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.open.count.check"));
            }
            // 预减获取红包剩余数量，decr原子减来防止领取人数超过红包个数
            Long decrement = redisTemplate.opsForValue().decrement(RedPacketUtils.GRAB_RED_PACKAGE_KEY + dto.getRedPacketId(), 1);
            if (decrement == null || decrement < 0) {
                log.info("拆红包失败, redPacketId:{}", dto.getRedPacketId());
                return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.open.count.check"));
            }
            //拆红包
            Integer redPacketAmount = redPacketUtils.unpackRedPacket(dto.getRedPacketId() + "", dto.getUserId());
            if (redPacketAmount == null || redPacketAmount == 0) {
                log.info("拆红包失败, redPacketId:{}", dto.getRedPacketId());
                return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.open.count.check"));
            }
            double redPacketAmountDouble = BigDecimal.valueOf(redPacketAmount.doubleValue() / 100).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            // 保存红包领取记录
            String xsUserId = SecurityUtils.getUser().getXsUserId();
            redPacketInfoService.saveRedPacketRecord(dto.getRedPacketId(), dto.getUserId(), byId.getType(), redPacketAmount,xsUserId);

            // 拆红包发送消息
            if("3".equals(dto.getChatType())){
                // 群里红包消息
                readMessage.sendReadPageMessage(byId,dto);
            }else{
                // 单聊红包消息
                readMessage.sendReadPrivateChatMessage(byId,dto);
            }

            return success(byId.getType().equals("0") ? redPacketAmountDouble : redPacketAmount);
        } catch (Exception e) {
            log.error("抢红包出错了{}", e);
            return ServerResponseEntity.showFailMsg(e.getMessage());
        } finally {
            RedisUtil.del("RED_PACKET:" + dto.getRedPacketId() + "-" + dto.getUserId());
        }
    }

    @PostMapping("/getRedAmount")
    @Operation(summary = "根据用户id 和 红包id 查询金额")
    public ServerResponseEntity<RedPacketRecord> getRedAmount(@RequestParam("userId") String userId,
                                                              @RequestParam("redPacketId") Long redPacketId) {
        return ServerResponseEntity.success(redPacketInfoService.getRedAmount(redPacketId, userId));
    }

    /**
     * 功能描述: NFT 红包
     *
     * @Author: LSR
     * @Date: 2023/2/24 11:00
     */
    @PostMapping("/sendNftRedPacket")
    @Operation(summary = "发送NFT红包")
    @Transactional
    public ServerResponseEntity<RedPacketVo> sendNftRedPacket(@RequestBody @Valid RedPacketInfoDto red) {
        String userId = SecurityUtils.getUser().getUserId();
        red.setUserId(userId);
        Tuple channelInfo = this.getChannelInfo(userId);
        if (red.getDawNum() == 0 || red.getTotalPacket() == 0) {
            throw new YamiShopBindException("yami.sys.illegalArgument");
        }
        if (StringUtils.isEmpty(channelInfo.get(0).toString())) {
            throw new YamiShopBindException("yami.chain.getcheck.fail");
        }
        if (StringUtils.isEmpty(channelInfo.get(2).toString()) || StringUtils.isEmpty(channelInfo.get(3).toString())) {
            throw new YamiShopBindException("yami.chain.getcheck.fail");
        }
        if (red.getTotalPacket() > red.getDawNum()) {
            throw new YamiShopBindException("yami.dtc.redpacket.personnft.minnum");
        }

        String decryptPassword = passwordManager.decryptPassword(red.getPassword());
        User user = userService.getById(userId);
        if (!passwordEncoder.matches(decryptPassword, user.getPayPassword())) {
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.password.check"));
        }
        // 扣gas
        userGasInfoService.reduceGasNumberByUserId(userId,red.getDawNum());
        red.setChainCode(channelInfo.get(2).toString());
        red.setChainType(channelInfo.get(3).toString());
        red.setChannelCode(channelInfo.get(0).toString());
        red.setChannelUserId(channelInfo.get(1).toString());
//        RedPacketVo redPacketVo = redPacketInfoService.sendNftRedPacket(red);

        // 1、保存红包记录
        if(ObjectUtils.isEmpty(red.getTotalPacket())){
            red.setTotalPacket(1);
        }
        // 下游商品ID转换
        String chainCode = "";
        String prodId = "";
        if("2".equals(channelInfo.get(3).toString())){
            LambdaQueryWrapper<Product> productId = new LambdaQueryWrapper<Product>().eq(Product::getSourceId, red.getProdId()).eq(Product::getSource,1);
            prodId = red.getProdId().toString();
            Product product = productService.getOne(productId);
            red.setProdId(product.getProdId());
            // 获取下游二级
            ProdNft dataByProdId = prodNftService.getDataByProdId(product.getProdId());
            red.setDenomId(dataByProdId.getDenomId());
            chainCode = product.getChain();
        }
        RedPacketInfo redPacketInfo = BeanUtil.copyProperties(red, RedPacketInfo.class);
        redPacketInfo.setType("1");
        redPacketInfo.setStatus(1);
        redPacketInfo.setRemainingPacket(redPacketInfo.getTotalPacket());
        redPacketInfo.setRemainingAmount(red.getDawNum().doubleValue());
        redPacketInfo.setTotalAmount(red.getDawNum().doubleValue());
        redPacketInfoService.save(redPacketInfo);
        RedPacketVo redPacketVo = RedPacketVo.builder()
                .redPacketId(redPacketInfo.getId())
                .title(redPacketInfo.getTitle())
                .type(redPacketInfo.getType())
                .build();
        // 2、冻结持仓 分为 DTC内部 与 下游平台 1:DTC 内部 2:外部导入平台
        if("1".equals(red.getChainType())){
            // =========查询币数量
            PersonNft personNft = PersonNft.builder().userId(red.getUserId()).status(0).build();
            personNft.setProductId(red.getProdId());
            List<PersonNft> personNfts = personNftService.listByParam(personNft);
            if(personNfts.size() < red.getDawNum()){
                throw new YamiShopBindException("yami.dtc.redpacket.check.personnft.num");
            }
            List<PersonNft> freezePerson = personNfts.subList(0, red.getDawNum());
            String contenStr = freezePerson.stream().map(PersonNft::getTokenId).collect(Collectors.joining(","));
            String dawProductCode = freezePerson.stream().map(PersonNft::getDawProductCode).collect(Collectors.joining(","));
            // =========冻结持仓
            // 1、添加记账表
            String applyId = IdUtil.getSnowflake().nextIdStr();
            PersonNftApply personNftAccount = PersonNftApply.builder()
                    .sceneType(SceneType.RedFreeze.getCode())
                    .content(contenStr)
                    .status(1)
                    .dawProductCode(dawProductCode)
                    .denomId(freezePerson.get(0).getDenomId())
                    .chainCode(freezePerson.get(0).getChainCode())
                    .channelCode(freezePerson.get(0).getChannelCode())
                    .channelType(red.getType())
                    .createTime(DateUtil.date())
                    .id(applyId)
                    .userId(red.getUserId())
                    .count(red.getDawNum())
                    .productId(freezePerson.get(0).getProductId())
                    .remark(redPacketInfo.getId() + "")
                    .build();
            personNftApplyMapper.save(personNftAccount);
            // 2、冻结持仓
            freezePerson.stream().forEach(s->s.setStatus(1));
            personNftService.updateBatch(freezePerson);
            // 保存红包Token记录
            redTokenRecordService.saveBatchByTokens(
                    applyId,
                    freezePerson.get(0).getDenomId(),
                    contenStr,
                    dawProductCode,
                    redPacketInfo.getId());
        }
        else if("2".equals(red.getChainType()))
        {
            Map<String, String> stringObjectMap = new HashMap<>();
            stringObjectMap.put("userId",red.getChannelUserId());
            stringObjectMap.put("channelCode",red.getChannelCode());
            stringObjectMap.put("count",redPacketInfo.getDawNum().toString());
            stringObjectMap.put("productId",prodId);
            stringObjectMap.put("sceneType","17");
            stringObjectMap.put("chainCode",chainCode);

            String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/freeze?";
            JSONObject jsonObject = dataWebService.hutoolPostWebService(url, stringObjectMap,null,null);
            if (null == jsonObject || jsonObject.getInteger("code") != Constant.SUCCESS_CODE ) {
                log.info("持仓数量不足,{}",jsonObject.getString("msg"));
                throw new YamiShopBindException( "可发送数量最大为："+jsonObject.getString("msg"));
            }

            redTokenRecordService.saveBatchByTokens(
                    jsonObject.getJSONObject("data").getString("applyId"),
                    jsonObject.getJSONObject("data").getString("denomId"),
                    jsonObject.getJSONObject("data").getString("tokensIds"),
                    jsonObject.getJSONObject("data").getString("productCodes"),
                    redPacketInfo.getId());
        }
        // 抢红包资格缓存
        RedPacketBasic redPacketBasic = RedPacketBasic
                .builder()
                .totalPacket(redPacketInfo.getTotalPacket())
                .totalAmount(redPacketInfo.getDawNum())
                .build();
        redisTemplate.opsForValue().set(GRAB_RED_PACKAGE_KEY + redPacketInfo.getId(), redPacketBasic.getTotalAmount(), RedPacketUtils.RED_PACKET_EXPIRE, TimeUnit.SECONDS);
        // 红包个数和总金额存入缓存
        redisTemplate.opsForValue().set(RED_PACKAGE_KEY + redPacketInfo.getId(), redPacketBasic, RedPacketUtils.RED_PACKET_EXPIRE, TimeUnit.SECONDS);


        // DTC++ gas 记录保存
        UserGasLog userGasLog = new UserGasLog();
        userGasLog.setCreateTime(new Date());
        userGasLog.setIoType(0); // 收支类型 0支出 1收入
        userGasLog.setType(5);   // gas记录 类型
        userGasLog.setIsPayed(1);  // 0未支付
        userGasLog.setPayNo(redPacketVo.getRedPacketId().toString());  // 支付单号
        userGasLog.setUserId(userId);
        userGasLog.setGasId(redPacketVo.getRedPacketId());
        userGasLog.setTabStatus(1); //已处理--- 已发送
        userGasLog.setPateTab(red.getChannelCode());  //平台
        userGasLog.setGasNum(red.getDawNum());
        userGasLogService.save(userGasLog);
        return success(redPacketVo);
    }

    /**
     * 功能描述: GAS 红包
     *
     * @Author: LSR
     * @Date: 2023/2/24 11:00
     */
    @PostMapping("/sendNftGASRedPacket")
    @Operation(summary = "发送GAS红包")
    @Transactional
    public ServerResponseEntity<RedPacketVo> sendGasRedPacket(@RequestBody @Valid RedPacketInfoDto red) {
        if (red.getGasNum() == 0 || red.getTotalPacket() == 0) {
            throw new YamiShopBindException("yami.sys.illegalArgument");
        }
        if (StringUtils.isEmpty(red.getChannelCode())) {
            throw new YamiShopBindException("yami.chain.getcheck.fail");
        }
        if (StringUtils.isEmpty(red.getChannelUserId())) {
            throw new YamiShopBindException("yami.chain.getcheck.fail");
        }
        if (red.getTotalPacket() > red.getGasNum()) {
            throw new YamiShopBindException("yami.dtc.redpacket.gas.minnum");
        }
        String userId = SecurityUtils.getUser().getUserId();
        if(!userId.equals(red.getUserId())){
            throw new YamiShopBindException("yami.sys.illegalArgument");
        }
        String decryptPassword = passwordManager.decryptPassword(red.getPassword());
        User user = userService.getById(userId);
        if (!passwordEncoder.matches(decryptPassword, user.getPayPassword())) {
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.password.check"));
        }
        red.setChannelCode(red.getChannelCode());
        red.setChannelUserId(red.getChannelUserId());
        RedPacketVo redPacketVo = redPacketInfoService.sendGasRedPacket(red);
        // DTC++ gas 记录保存
        UserGasLog userGasLog = new UserGasLog();
        userGasLog.setCreateTime(new Date());
        userGasLog.setIoType(0); // 收支类型 0支出 1收入
        userGasLog.setType(4);   // gas记录 类型
        userGasLog.setIsPayed(1);  // 0未支付
        userGasLog.setPayNo(redPacketVo.getRedPacketId().toString());  // 支付单号
        userGasLog.setUserId(userId);
        userGasLog.setGasId(redPacketVo.getRedPacketId());
        userGasLog.setTabStatus(1); //已处理--- 已发送
        userGasLog.setPateTab(red.getChannelCode());  //平台
        userGasLog.setGasNum(red.getGasNum());
        userGasLogService.save(userGasLog);
        return success(redPacketVo);
    }

    /**
     * 功能描述: DTC GAS 红包
     *
     * @Author:
     * @Date: 2023/5/11 10:00
     */
    @PostMapping("/sendGasRedPacket")
    @Operation(summary = "发送DTC-GAS红包")
    @Transactional
    public ServerResponseEntity<RedPacketVo> sendDtcGasRedPacket(@RequestBody @Valid RedPacketInfoDto red) {
        if(ObjectUtils.isEmpty(red.getTotalPacket())){
            red.setTotalPacket(1);
        }
        if (red.getGasNum() == 0 || red.getTotalPacket() == 0) {
            throw new YamiShopBindException("yami.sys.illegalArgument");
        }
        if (red.getTotalPacket() > red.getGasNum()) {
            throw new YamiShopBindException("yami.dtc.redpacket.gas.minnum");
        }
        String userId = SecurityUtils.getUser().getUserId();
        if(!userId.equals(red.getUserId())){
            throw new YamiShopBindException("yami.sys.illegalArgument");
        }
        String decryptPassword = passwordManager.decryptPassword(red.getPassword());
        User user = userService.getById(userId);
        if (!passwordEncoder.matches(decryptPassword, user.getPayPassword())) {
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.password.check"));
        }
        UserGasInfo gasInfo = userGasInfoService.getOne(new LambdaQueryWrapper<UserGasInfo>().eq(UserGasInfo::getUserId, userId));
        if (Objects.isNull(gasInfo) || Objects.isNull(gasInfo.getGasNumber()) || gasInfo.getGasNumber() < red.getGasNum()) {
            throw new YamiShopBindException("yami.dtc.redpacket.check.gas.num");
        }
        //预扣GAS值
        gasInfo.setGasNumber(gasInfo.getGasNumber() - red.getGasNum());
        userGasInfoService.updateById(gasInfo);
        RedPacketVo redPacketVo = redPacketInfoService.sendGasRedPacket(red);
        // DTC++ gas 记录保存
        UserGasLog userGasLog = new UserGasLog();
        userGasLog.setCreateTime(new Date());
        userGasLog.setIoType(0); // 收支类型 0支出 1收入
        userGasLog.setType(4);   // gas记录 类型
        userGasLog.setIsPayed(1);  // 0未支付
        userGasLog.setPayNo(redPacketVo.getRedPacketId().toString());  // 支付单号
        userGasLog.setUserId(userId);
        userGasLog.setGasId(redPacketVo.getRedPacketId());
        userGasLog.setTabStatus(1); //已处理--- 已发送
        userGasLog.setGasNum(red.getGasNum());
        userGasLogService.save(userGasLog);
        return success(redPacketVo);
    }


//    @GetMapping("/redPacketTask")
    public void redPacketTask() {
        logger.info("1分钟 ================红包过期定时任务=====================");
        {
            // 获取过期的红包
            // TODO 测试修改 红包过期时间
            List<RedPacketInfo> hours = redPacketInfoMapper.getHours();
            for (RedPacketInfo redPacketInfo : hours) {
                // 删除Redis 缓存
                String redPackageKey = RED_PACKAGE_KEY + redPacketInfo.getId();
                String grabRedPackageKey = GRAB_RED_PACKAGE_KEY + redPacketInfo.getId();
                String redPackageConsumeKey = RED_PACKAGE_CONSUME_KEY + redPacketInfo.getId();
                RedisUtil.del(redPackageKey, grabRedPackageKey, redPackageConsumeKey);
                // 添加退款记录
                // 记录本次拆红包
                if (redPacketInfo.getRemainingAmount() > 0 && redPacketInfo.getRemainingPacket() > 0) {
                    RedPacketRecord redPacketRecord = RedPacketRecord.builder()
                            .redPacketId(redPacketInfo.getId())
                            .amount(redPacketInfo.getRemainingAmount())
//                        .createTime(LocalDateTime.now())
                            .userId(redPacketInfo.getUserId())
                            .type(redPacketInfo.getType())
                            .recType(2)
                            .build();
                    redPacketRecordService.save(redPacketRecord);
                }
                redPacketInfo.setStatus(2);
            }
            // 修改红包状态
            redPacketInfoService.updateBatchById(hours);
        }
    }

    /**
     * 定时任务处理红包抽取记录
     */
    @GetMapping("redPacketRecordTask")
    public void redPacketRecordTask() {
        logger.info("30秒 ================红包抽取记录定时任务=====================");
        // 获取待处理红包领取记录
        QueryWrapper<RedPacketRecord> redPacketRecordQueryWrapper = new QueryWrapper<>();
        redPacketRecordQueryWrapper.eq("status", 0);
        List<RedPacketRecord> redPacketRecordList = redPacketRecordService.list(redPacketRecordQueryWrapper);
        redPacketRecordList.forEach(redPacketRecord -> {
            RedPacketInfo byId = redPacketInfoService.getById(redPacketRecord.getRedPacketId());
            // 获取红包记录总和
            QueryWrapper<RedPacketRecord> queryWrapper = new QueryWrapper();
            queryWrapper.eq("red_packet_id", redPacketRecord.getRedPacketId());
            List<RedPacketRecord> list = redPacketRecordService.list(queryWrapper);
            double sumNum = list.stream().mapToDouble(RedPacketRecord::getAmount).sum();
            if (sumNum > byId.getTotalAmount()) {
                logger.error("红包总额错误");
                redPacketRecord.setStatus(2);
                redPacketRecordService.updateById(redPacketRecord);
                throw new YamiShopBindException("yami.dtc.redpacket.check.amount.error");
            }
            switch (redPacketRecord.getType()) {
                // 人民币红包 ---------  调用支付接口
                case "0":
                    logger.info("人民币定时任务");
                    // 获取新生user_id
                    User userDetail = userService.getUserDetail(byId.getUserId());
                    try {
                        userBalanceService.receiveRedPacketSaveUserBalanceData(userDetail.getXsUserId(), userDetail.getUserId(),
                                redPacketRecord.getXsUserId(), redPacketRecord.getUserId(),
                                redPacketRecord.getAmount(),
                                redPacketRecord.getRecType() + "",
                                redPacketRecord.getRedPacketId(),
                                redPacketRecord.getId());
                        // 修改数据
                        redPacketRecord.setStatus(1);
                        redPacketRecordService.updateById(redPacketRecord);
                    } catch (Exception e) {
                        logger.info("人民币定时任务错误" + e);
                        redPacketRecord.setStatus(2);
                        redPacketRecordService.updateById(redPacketRecord);
                    }
                    break;
                // NFT红包 ----------- 调用转增接口
                case "1":
                    redPacketRecord.setStatus(1);
                    String tokens = "";
                    try{
                        // 获取token
                        tokens = getTokenByDtc(byId, redPacketRecord);
                        logger.info("获取到的token{}",tokens);
                    }catch (Exception e){
                        logger.error("红包领取定时任务异常{}", e);
                        redPacketRecord.setStatus(2);
                        redPacketRecordService.updateById(redPacketRecord);
                        break;
                    }
                    // 如果是领取调用转增接口
                    if (redPacketRecord.getRecType() == 1) {
                        // typr 1 为 DTC 2 为 外部导入
                        if("1".equals(byId.getChainType())){
                            // DTC 红包 转赠
                            try{
                                redPacketDrawPersonnft(tokens, redPacketRecord.getUserId(), redPacketRecord.getRedPacketId());
                            }catch (Exception e){
                                redPacketRecord.setStatus(2);
                                logger.error("红包定时任务---DTC红包转赠异常{}",e);
                            }
                        }else if("2".equals(byId.getChainType())){
                            try {
                            // 获取接收人下游userId
                            ChannelUserRelationRecord toUser = channelUserRelationRecordService.getOne(new QueryWrapper<ChannelUserRelationRecord>()
                                    .lambda()
                                    .eq(ChannelUserRelationRecord::getUserId, redPacketRecord.getUserId())
                                    .eq(ChannelUserRelationRecord::getStatus, 0)
                                    .eq(ChannelUserRelationRecord::getChannelCode, byId.getChannelCode())
                                    .eq(ChannelUserRelationRecord::getChainCode,byId.getChainCode())
                                    .eq(ChannelUserRelationRecord::getType,byId.getChainType())
                                    .last("limit 1"));

                            // 获取发送人下游userId
                            ChannelUserRelationRecord formUser = channelUserRelationRecordService.getOne(new QueryWrapper<ChannelUserRelationRecord>()
                                    .lambda()
                                    .eq(ChannelUserRelationRecord::getUserId, byId.getUserId())
                                    .eq(ChannelUserRelationRecord::getStatus, 0)
                                    .eq(ChannelUserRelationRecord::getChannelCode, byId.getChannelCode())
                                    .eq(ChannelUserRelationRecord::getChainCode,byId.getChainCode())
                                    .eq(ChannelUserRelationRecord::getType,byId.getChainType())
                                    .last("limit 1"));
                            // 获取applyId
                            QueryWrapper<RedTokenRecord> redTokenRecordQueryWrapper = new QueryWrapper<>();
                            redTokenRecordQueryWrapper.eq("tokens_id",Arrays.asList(tokens.split(",")).get(0));
                            redTokenRecordQueryWrapper.eq("red_id",byId.getId());
                            redPacketRecordQueryWrapper.last("limit 1");
                            RedTokenRecord one = redTokenRecordService.getOne(redTokenRecordQueryWrapper);
                            Map<String, String> stringObjectMap1 = new HashMap<>();
                            stringObjectMap1.put("tokenIds", tokens);
                            stringObjectMap1.put("formUserId", formUser.getChannelUserId());
                            stringObjectMap1.put("toUserId", toUser.getChannelUserId());
                            stringObjectMap1.put("type", "1");
                            stringObjectMap1.put("channelCode", byId.getChannelCode());
                            stringObjectMap1.put("id", one.getApplyId());
                            String url1 = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/transferPerson?";
//                        String url1 = "http://localhost:9206/outapi/app/personnftApply/redPacketDrawPersonnft?";
                            JSONObject jsonObject1 = new JSONObject();
                                jsonObject1 = dataWebService.hutoolPostWebService(url1, stringObjectMap1,null,null);
                                if (null == jsonObject1 || jsonObject1.getInteger("code") != Constant.SUCCESS_CODE ) {

                                    throw new YamiShopBindException( jsonObject1.getString("msg"));
                                }
                            } catch (Exception e) {
                                redPacketRecord.setStatus(2);
                            }
                        }
                    }
                    // 如果是领取调用解冻接口
                    else if (redPacketRecord.getRecType() == 2 || redPacketRecord.getRecType() == 3) {
                        // typr 1 为 DTC 2 为 外部导入
                        if("1".equals(byId.getChainType())){
                            logger.info("退回解冻{}",tokens);
                            try{
                                unfreezePersonnft(redPacketRecord.getUserId(),redPacketRecord.getAmount().intValue(),redPacketRecord.getRedPacketId(),tokens);
                            }catch (Exception e){
                                redPacketRecord.setStatus(2);
                                logger.error("红包定时任务---退回解冻异常{}",e);
                            }
                        }else if("2".equals(byId.getChainType())){
                            // 获取下游UserId
                            ChannelUserRelationRecord channelUserRelationRecord = channelUserRelationRecordService.getOne(new QueryWrapper<ChannelUserRelationRecord>()
                                    .lambda()
                                    .eq(ChannelUserRelationRecord::getUserId, redPacketRecord.getUserId())
                                    .eq(ChannelUserRelationRecord::getStatus, 0)
                                    .eq(ChannelUserRelationRecord::getChannelCode, byId.getChannelCode())
                                    .eq(ChannelUserRelationRecord::getChainCode,byId.getChainCode())
                                    .eq(ChannelUserRelationRecord::getType,byId.getChainType())
                                    .last("limit 1"));
                            // 获取下游商品ID
                            Product product = productService.getOne(Wrappers.lambdaQuery(Product.class).eq(Product::getProdId, byId.getProdId()).eq(Product::getSource,"1"));
                            // 获取applyId
                            QueryWrapper<RedTokenRecord> redTokenRecordQueryWrapper = new QueryWrapper<>();
                            redTokenRecordQueryWrapper.eq("tokens_id",Arrays.asList(tokens.split(",")).get(0));
                            redTokenRecordQueryWrapper.eq("red_id",byId.getId());
                            redPacketRecordQueryWrapper.last("limit 1");
                            RedTokenRecord one = redTokenRecordService.getOne(redTokenRecordQueryWrapper);
                            Map<String, String> stringObjectMap1 = new HashMap<>();
                            stringObjectMap1.put("tokenIds", tokens);
                            stringObjectMap1.put("userId", channelUserRelationRecord.getChannelUserId());
                            stringObjectMap1.put("productId", product.getSourceId().toString());
                            stringObjectMap1.put("channelCode", byId.getChannelCode());
                            stringObjectMap1.put("status", "0");
                            stringObjectMap1.put("id", one.getApplyId());
                            // 发布测试修改
                            String url2 = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/unFreeze?";
//                        String url2 = "http://localhost:9206/outapi/app/personnftApply/freezePersonnft?";
                            JSONObject jsonObject2 = new JSONObject();
                            try {
                                jsonObject2 = dataWebService.hutoolPostWebService(url2, stringObjectMap1,null,null);
                                if (null == jsonObject2 || jsonObject2.getInteger("code") != Constant.SUCCESS_CODE ) {
                                    throw new YamiShopBindException( jsonObject2.getString("msg"));
                                }
                            } catch (Exception e) {
                                redPacketRecord.setStatus(2);
                            }
                        }
                        // 红包退回Gas新增 退回记录
                        if(redPacketRecord.getRecType() == 2 && redPacketRecord.getStatus() == 1) {
                            // 添加 gas
                            userGasInfoService.saveGasNumberByUserId(redPacketRecord.getUserId(),redPacketRecord.getAmount().intValue());
                            // 添加记录
                            UserGasLog userGasLog = new UserGasLog();
                            userGasLog.setCreateTime(new Date());
                            userGasLog.setIoType(2); // 收支类型 0支出 1收入
                            userGasLog.setType(5);   // gas记录 类型
                            userGasLog.setIsPayed(1);  // 0未支付
                            userGasLog.setPayNo(redPacketRecord.getRedPacketId().toString());  // 支付单号
                            userGasLog.setUserId(redPacketRecord.getUserId());
                            userGasLog.setGasId(redPacketRecord.getId());
                            userGasLog.setTabStatus(1); //已处理--- 已发送
                            userGasLog.setPateTab(byId.getChannelCode());  //平台
                            userGasLog.setGasNum(redPacketRecord.getAmount().intValue());
                            userGasLogService.save(userGasLog);
                        }
                    }
                    // 保存数据
                    redPacketRecord.setTokenId(tokens);
                    redPacketRecordService.updateById(redPacketRecord);
                    break;
                case "2":
                    // Gas红包 ----------- 调用gas增加接口
                    try {
                        // 添加Gas
                        userGasInfoService.saveGasNumberByUserId(redPacketRecord.getUserId(), redPacketRecord.getAmount().intValue());

                        // DTC++ 添加Gas记录
                        UserGasLog userGasLog = new UserGasLog();
                        userGasLog.setCreateTime(new Date());
                        userGasLog.setUserId(redPacketRecord.getUserId());
                        userGasLog.setIoType(redPacketRecord.getRecType() == 2 ? 2 : 1); // 收支类型 0支出 1收入
                        userGasLog.setType(4);   // gas 记录类型
                        userGasLog.setIsPayed(1);  // 0未支付
                        userGasLog.setPayNo(redPacketRecord.getId().toString());  // 支付单号
                        userGasLog.setToUserId(byId.getUserId()); // 发红包用户id
                        userGasLog.setGasId(byId.getId());
                        userGasLog.setTabStatus(1); //已处理--- 已发送
                        userGasLog.setGasNum(redPacketRecord.getAmount().intValue());
                        userGasLogService.save(userGasLog);

                        // 修改数据
                        redPacketRecord.setStatus(1);
                        redPacketRecord.setGasNum(redPacketRecord.getAmount().intValue());
                        redPacketRecordService.updateById(redPacketRecord);
                    } catch (Exception e) {
                        logger.error("gas红包发送异常{}",e);
                        redPacketRecord.setStatus(2);
                        redPacketRecordService.updateById(redPacketRecord);
                    }
                    break;
            }
        });
    }


    private void unfreezePersonnft( String userId, Integer tokenNum, Long redPacketId, String tokenIds) {
        {
            // 查询对应持仓个数
            PersonNft personNft = PersonNft.builder().status(1).userId(userId).build();
            PersonNftApply personNftApply = personNftApplyMapper.selectByRedIdAndUserId(redPacketId,userId,"");
            personNft.setDenomId(personNftApply.getDenomId());
            personNft.setTokenIds(Arrays.asList(tokenIds.split(",")));
            List<PersonNft> personNfts = personNftService.listByParam(personNft);
            if(personNfts.size() < tokenNum){
                throw new YamiShopBindException("yami.dtc.redpacket.check.personnft.status");
            }
            // 添加账单表
            List<PersonNft> freezePerson = personNfts.subList(0, tokenNum);
            String contenStr = String.join(",",freezePerson.stream().map(s -> s.getTokenId()).collect(Collectors.toList()));
            String dawProductCode = String.join(",",freezePerson.stream().map(s -> s.getDawProductCode()).collect(Collectors.toList()));

            // 自己领取自己红包 / 红包退回 -- 解冻过程
            PersonNftAccount personNftAccount = PersonNftAccount.builder()
                    .sceneType(Integer.valueOf(SceneType.RedAdd.getCode()))
                    .content(contenStr)
                    .dawProductCode(dawProductCode)
//                .dawNameId(freezePerson.get(0).getDawNameId())
                    .denomId(freezePerson.get(0).getDenomId())
                    .userId(userId)
                    .createTime(DateUtil.date())
                    .id(IdUtil.getSnowflake().nextIdStr())
                    .count(tokenNum)
                    .channelType(personNftApply.getChannelType())
                    .channelCode(personNftApply.getChannelCode())
                    .chainCode(personNftApply.getChainCode())
                    .productId(freezePerson.get(0).getProductId())
                    .orderId(redPacketId+"")
                    .build();
            personNftAccountMapper.save(personNftAccount);
            //5 转增方转增记录
            PersonNftAccount personNftAccount1 = PersonNftAccount.builder()
                    .sceneType(Integer.valueOf(SceneType.RedTransfer.getCode()))
                    .content(contenStr)
                    .dawProductCode(dawProductCode)
//                    .dawNameId(freezePerson.get(0).getDawNameId())
                    .denomId(freezePerson.get(0).getDenomId())
                    .userId(userId)
                    .createTime(DateUtil.date())
                    .id(IdUtil.getSnowflake().nextIdStr())
                    .count(tokenNum)
                    .channelType(personNftApply.getChannelType())
                    .channelCode(personNftApply.getChannelCode())
                    .chainCode(personNftApply.getChainCode())
                    .productId(freezePerson.get(0).getProductId())
                    .orderId(redPacketId+"")
                    .build();
            personNftAccountMapper.save(personNftAccount1);
            // 冻结持仓
            freezePerson.stream().forEach(s->s.setStatus(0));
            personNftService.updateBatch(freezePerson);
        }
    }

    private void redPacketDrawPersonnft(String tokenIds, String userId, Long redPacketId) {
        logger.info("获取Token{}",tokenIds);
        PersonNftApply personNftApply = personNftApplyMapper.selectByRedIdAndUserId(redPacketId,"","");
        List<PersonNft> lsitAdd = new ArrayList<>();
        List<PersonNft> lsit = new ArrayList<>();
        List<String> tokenList = Arrays.asList(tokenIds.split(","));
        List<String> prodCode = new ArrayList<>();
        for (String tokenId: tokenList) {
            //1增加受赠方持仓
            PersonNft personNft = PersonNft.builder().tokenId(tokenId).status(4).build();
            List<PersonNft> personNfts = personNftService.listByParam(personNft);
            //校验受赠方是否有该未删除的tokenid
            List<PersonNft> list = personNfts.stream().filter(s -> s.getUserId().equals(userId)&&s.getStatus()!=2).collect(Collectors.toList());
            if(list.size()>0){
                throw new YamiShopBindException("yami.dtc.redpacket.check.personnft.recipient.error");
            }
            List<PersonNft> list1 = personNfts.stream().filter(s -> s.getUserId().equals(userId)&&s.getStatus()==2).collect(Collectors.toList());
            if(list1.size()>0){
                //如果受赠方已有记录直接修改状态
                PersonNft personNft1 = list1.get(0);
                prodCode.add(personNft1.getDawProductCode());
                personNft1.setStatus(0);
                personNft1.setCreateTime(DateUtil.date());
                personNft1.setSceneType(Integer.valueOf(SceneType.RedAdd.getCode()));
                lsit.add(personNft1);
            }else{
                //受赠方添加持仓 -没有新增一条
                PersonNft personNft1 = personNfts.get(0);
                prodCode.add(personNft1.getDawProductCode());
                PersonNft person = PersonNft.builder()
                        .status(0)
                        .id(IdUtil.getSnowflake().nextIdStr())
                        .createTime(DateUtil.date())
                        .userId(userId)
                        .tokenId(tokenId)
                        .productId(personNftApply.getProductId())
                        .dawProductCode(personNft1.getDawProductCode())
                        .denomId(personNftApply.getDenomId())
//                        .DawNameId(personNftApply.getDawNameId());
                        .chainCode(personNftApply.getChainCode())
                        .channelCode(personNftApply.getChannelCode())
                        .sceneType(Integer.valueOf(SceneType.RedAdd.getCode()))
                        .build();
                lsitAdd.add(person);
            }
            //4 转增方减去持仓
            List<PersonNft> personNfts2 = personNfts.stream().filter(s -> s.getUserId().equals(personNftApply.getUserId())&&s.getStatus()==1).collect(Collectors.toList());
            if(personNfts2.size()!=1){
                throw new YamiShopBindException("yami.dtc.redpacket.check.personnft.Transferor.error");
            }else{
                //受赠方减去持仓
                PersonNft personNft1 = personNfts2.get(0);
                personNft1.setStatus(2);
                personNft1.setSceneType(Integer.valueOf(SceneType.RedTransfer.getCode()));
                personNft1.setUpdateTime(DateUtil.date());
                lsit.add(personNft1);
            }
        }
        if(lsit.size()>0){
            personNftService.updateBatchById(lsit);
        }
        if(lsitAdd.size()>0){
            personNftService.saveBatch(lsitAdd);
        }
        //2增加受赠方藏品记录
        String idStr = IdUtil.getSnowflake().nextIdStr();
        PersonNftAccount personNftAccount = PersonNftAccount.builder()
                .sceneType(Integer.valueOf(SceneType.RedAdd.getCode()))
                .content(tokenIds)
                .dawProductCode(String.join(",",prodCode))
//                .dawNameId(personNftApply.getDawNameId())
                .denomId(personNftApply.getDenomId())
                .userId(userId)
                .createTime(DateUtil.date())
                .id(idStr)
                .count(tokenList.size())
                .productId(personNftApply.getProductId())
                .orderId(redPacketId+"")
                .channelType(personNftApply.getChannelType())
                .chainCode(personNftApply.getChainCode())
                .channelCode(personNftApply.getChannelCode())
                .build();
        personNftAccountMapper.save(personNftAccount);
        //5 转增方转增记录
        PersonNftAccount personNftAccount1 = PersonNftAccount.builder()
                .sceneType(Integer.valueOf(SceneType.RedTransfer.getCode()))
                .content(tokenIds)
                .dawProductCode(String.join(",",prodCode))
//                .dawNameId(personNftApply.getDawNameId())
                .denomId(personNftApply.getDenomId())
                .userId(personNftApply.getUserId())
                .createTime(DateUtil.date())
                .id(IdUtil.getSnowflake().nextIdStr())
                .count(tokenList.size())
                .productId(personNftApply.getProductId())
                .orderId(redPacketId+"")
                .chainCode(personNftApply.getChainCode())
                .channelCode(personNftApply.getChannelCode())
                .channelType(personNftApply.getChannelType())
                .build();
        personNftAccountMapper.save(personNftAccount1);
        List<AssetTrendsVO> list = new ArrayList<>();
        logger.info("红包领取成功，完成增加持仓=================进入红包记账");
        for (String tokenId : tokenList) {
            AssetTrendsVO trendsVO = AssetTrendsVO.builder().denomId(personNftApply.getDenomId()).tokenId(tokenId)
                    .fromUserId(personNftApply.getUserId()).toUserId(userId).outId(idStr).prodId(personNftApply.getProductId()).build();
            list.add(trendsVO);
        }
        applicationContext.publishEvent(new AssetTrendsEvent(TradeType.RED_ENVELOPE.getValue(), list));
        logger.info("==========红包领取成功，红包记账完成=============");
    }

    private String getTokenByDtc(RedPacketInfo byId, RedPacketRecord redPacketRecord) {
        // 获取 未使用的token
        QueryWrapper<RedTokenRecord> redTokenRecordQueryWrapper = new QueryWrapper<>();
        redTokenRecordQueryWrapper.eq("red_id",byId.getId());
        redTokenRecordQueryWrapper.eq("status","0");
        redTokenRecordQueryWrapper.last(" limit "+redPacketRecord.getAmount().intValue());
        List<RedTokenRecord> list = redTokenRecordService.list(redTokenRecordQueryWrapper);
        applyId = list.get(0).getApplyId();
        list.forEach(s->{
            s.setStatus(redPacketRecord.getRecType().toString());
        });
        // 修改查询出 token 的状态
        redTokenRecordService.updateBatchById(list);
        List<String> collect = list.stream().map(RedTokenRecord::getTokensId).collect(Collectors.toList());
        return String.join(",",collect);
    }


//    public static void main(String[] args) {
//        test2(new BigDecimal("0.1"),new BigDecimal("0.01"),new BigDecimal("3"));
//    }

    /**
     * 功能描述: 二倍均值法
     * @Author: LSR
     * @Date: 2023/3/21 16:44
     */
    private static void test2(BigDecimal amount,BigDecimal min ,BigDecimal num){
        BigDecimal remain = amount.subtract(min.multiply(num));
        final Random random = new Random();
        final BigDecimal hundred = new BigDecimal("100");
        final BigDecimal two = new BigDecimal("2");
        BigDecimal sum = BigDecimal.ZERO;
        BigDecimal redpeck;
        for (int i = 0; i < num.intValue(); i++) {
            final int nextInt = random.nextInt(100);
            if(i == num.intValue() -1){
                redpeck = remain;
            }else{
                redpeck = new BigDecimal(nextInt).multiply(remain.multiply(two).divide(num.subtract(new BigDecimal(i)),2, RoundingMode.CEILING)).divide(hundred,2, RoundingMode.FLOOR);
            }
            if(remain.compareTo(redpeck) > 0){
                remain = remain.subtract(redpeck);
            }else{
                remain = BigDecimal.ZERO;
            }
            sum = sum.add(min.add(redpeck));
            System.out.println("第"+(i+1)+"个人抢到红包金额为："+min.add(redpeck));
        }
        System.out.println("校验每个红包累计额度是否等于红包总额结果："+amount.compareTo(sum));
    }
}
